package com.bestcem.xm.deliver.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bestcem.xm.common.core.constant.AppRequestErrorCode;
import com.bestcem.xm.common.core.constant.AppResourceErrorCode;
import com.bestcem.xm.common.core.constant.ReqErrorCodeConstants;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ValidationErrorCodeEnum;
import com.bestcem.xm.common.core.exception.BusinessException;
import com.bestcem.xm.common.core.oss.enums.OssPathEnum;
import com.bestcem.xm.common.core.uitls.DynamicEasyExcelImportUtil;
import com.bestcem.xm.common.core.uitls.SignUtil;
import com.bestcem.xm.component.mybatis.service.impl.XmServiceImpl;
import com.bestcem.xm.component.security.context.SecurityContextHolder;
import com.bestcem.xm.componet.filestorage.service.StorageService;
import com.bestcem.xm.deliver.controller.param.SmsRecordsPageParam;
import com.bestcem.xm.deliver.controller.v2.param.MemberDeliverDataByMobile;
import com.bestcem.xm.deliver.controller.v2.param.SmsDeliversParam;
import com.bestcem.xm.deliver.controller.v2.param.SmsDeliversParamAgain;
import com.bestcem.xm.deliver.controller.v2.vo.DeliverSmsRecordVo;
import com.bestcem.xm.deliver.convert.DeliverConvertMapper;
import com.bestcem.xm.deliver.entity.*;
import com.bestcem.xm.deliver.enums.*;
import com.bestcem.xm.deliver.grpc.client.*;
import com.bestcem.xm.deliver.grpc.client.dto.OrgInfoDto;
import com.bestcem.xm.deliver.grpc.v1.services.DeliverChannel;
import com.bestcem.xm.deliver.grpc.v1.services.SMSRecordSType;
import com.bestcem.xm.deliver.grpc.v1.services.SMSRecordStatus;
import com.bestcem.xm.deliver.mapper.*;
import com.bestcem.xm.deliver.mq.dto.SmsDeliverMessageDto;
import com.bestcem.xm.deliver.mq.send.biz.DeliverMessageSendService;
import com.bestcem.xm.deliver.service.DeliverDeliverService;
import com.bestcem.xm.deliver.service.DeliverEmailDeliverService;
import com.bestcem.xm.deliver.service.DeliverSmsDeliverService;
import com.bestcem.xm.messagecenter.grpc.v1.services.MessageCenterTemplate;
import com.bestcem.xm.qdes.grpc.v1.services.Project;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.bestcem.xm.common.core.constant.Constants.SEPARATOR;
import static com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum.STATUS_CHANGED;
import static com.bestcem.xm.common.core.uitls.CommonUtil.URL_REGEX;
import static com.bestcem.xm.deliver.enums.DeliverStatusEnum.DELIVER_STATUS_START;
import static com.bestcem.xm.deliver.enums.DeliverStatusEnum.DELIVER_STATUS_STOP;
import static com.bestcem.xm.deliver.enums.DeliverSurveyDataSurveyStatusEnum.DELIVERSURVEYDATA_SURVEY_STATUS_UNANSWER;
import static com.bestcem.xm.deliver.enums.DeliverTtypeEnum.DELIVER_TTYPE_SMS;
import static com.bestcem.xm.deliver.enums.RespondentStatusEnum.RESPONDENT_STATUS_FINISH;
import static com.bestcem.xm.deliver.enums.RespondentStatusEnum.RESPONDENT_STATUS_NOTSTART;
import static com.bestcem.xm.deliver.enums.SmsRecordStatusEnum.*;
import static com.bestcem.xm.deliver.enums.SurverySubmitTyeEnum.LIMITED_ONE_IN_DELIVER_GROUP_SUBMINT_TYPE;
import static com.bestcem.xm.deliver.enums.SurverySubmitTyeEnum.LIMITED_ONE_SURVERY_SUBMINT_TYPE;
import static com.bestcem.xm.deliver.grpc.v1.services.DeliverAwardUseType.DELIVER_AWARD_USE_TYPE_UNUSE;
import static com.bestcem.xm.deliver.grpc.v1.services.DeliverAwardUseType.DELIVER_AWARD_USE_TYPE_USE;
import static com.bestcem.xm.deliver.grpc.v1.services.SMSRecordSType.*;
import static com.bestcem.xm.deliver.service.impl.DeliverEmailDeliverServiceImpl.EMAILDELIVER_EXPORT;
import static com.bestcem.xm.deliver.util.DeliverConstant.DELIVER_MQ_BATCH_SIZE;
import static com.bestcem.xm.deliver.util.DeliverConstant.RESPONDENT_STATUS;

/**
 * @author been
 * @description 针对表【ds_deliver_smsdeliver】的数据库操作Service实现
 * @createDate 2022-11-07 13:49:46
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DeliverSmsDeliverServiceImpl extends XmServiceImpl<DeliverSmsDeliverMapper, DeliverSmsDeliver> implements DeliverSmsDeliverService {

    private @NonNull DeliverSmsRecordMapper deliverSmsRecordMapper;
    private @NonNull DeliverDeliverMapper deliverDeliverMapper;
    private @NonNull DeliverSmsDeliverUrgeMapper deliverSmsDeliverUrgeMapper;
    private @NonNull DeliverDeliverGroupMapper deliverDeliverGroupMapper;
    private @NonNull DeliverDeliverSurveyDataMapper deliverDeliverSurveyDataMapper;
    private @NonNull DeliverSmsDeliverMemberIdMapper smsDeliverMemberIdMapper;
    private @NonNull DeliverConvertMapper deliverConvertMapper;

    private @NonNull DeliverDeliverService deliverService;
    private @NonNull DeliverEmailDeliverService emailDeliverService;

    private @NonNull UserGrpcClient userGrpcClient;
    private @NonNull MessageCenterClient messageCenterClient;
    private @NonNull SurveyGrpcClient surveyGrpcClient;
    private @NonNull MemberGrpcClient memberGrpcClient;
    private @NonNull QdesGrpcClient qdesGrpcClient;

    //private @NonNull OssService ossService;
    private @NonNull StorageService storageService;
    private @NonNull DeliverMessageSendService deliverMessageSendService;

    @Override
    public List<DeliverSmsDeliver> originGetSmsDeliverList(String deliverGroupId) {
        LambdaQueryWrapper<DeliverSmsDeliver> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverSmsDeliver::getDeliverId, deliverGroupId);
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public List<DeliverSmsRecord> getSmsRecordList(String memberId, List<String> smsDeliverList) {
        LambdaQueryWrapper<DeliverSmsRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverSmsRecord::getMemberId, memberId);
        queryWrapper.in(DeliverSmsRecord::getSmsDeliverId, smsDeliverList);
        queryWrapper.eq(DeliverSmsRecord::getSType, SMSRECORD_S_TYPE_URGE.getNumber());
        queryWrapper.orderByAsc(DeliverSmsRecord::getCreatedDt);
        queryWrapper.orderByDesc(DeliverSmsRecord::getUpdatedDt);
        return deliverSmsRecordMapper.selectList(queryWrapper);
    }

    @Override
    public void triggerDeliverStatus(DeliverDeliver deliver, String action) {
        DeliverSmsDeliver sms_deliver = Optional.ofNullable(baseMapper.selectOne(new QueryWrapper<DeliverSmsDeliver>().lambda().eq(DeliverSmsDeliver::getDeliverId, deliver.getId()))).orElseThrow(() -> new BusinessException(String.format("DeliverSmsDeliver[deliverId=%s] not found", deliver.getId())));
        JSONObject param = new JSONObject();
        param.put("version", deliver.getVersion());

        if (StrUtil.equals("done", action) && sms_deliver.getIsDelay().equals(0)) {
            deliverDeliverMapper.update(null, new UpdateWrapper<DeliverDeliver>().lambda().eq(DeliverDeliver::getId, deliver.getId()).set(DeliverDeliver::getStatus, DELIVER_STATUS_START.getValue()));
            //立即投放
            beforeDeliverSmsDeliver(sms_deliver, param, deliver, true, null);
        } else if (StrUtil.equals("done", action) && sms_deliver.getIsDelay().equals(1)) {
            //延迟投放
            if (LocalDateTime.now().isAfter(sms_deliver.getDeliverTime())) {
                //如果已经错过定时投放的投放时间，则状态为 未投放
                deliverDeliverMapper.update(null, new UpdateWrapper<DeliverDeliver>().lambda().eq(DeliverDeliver::getId, deliver.getId()).set(DeliverDeliver::getStatus, DELIVER_STATUS_STOP.getValue()));
                throw new BusinessException("投放时间过期");
            }

            Date delayDate = Date.from(sms_deliver.getDeliverTime().atZone(ZoneId.systemDefault()).toInstant());
            beforeDeliverSmsDeliver(sms_deliver, param, deliver, true, delayDate);
        } else if (StrUtil.equals("review_success", action) && sms_deliver.getIsDelay().equals(1)) {
            //延迟投放
            if (LocalDateTime.now().isAfter(sms_deliver.getDeliverTime())) {
                //如果已经错过定时投放的投放时间，则状态为 未投放
                deliverDeliverMapper.update(null, new UpdateWrapper<DeliverDeliver>().lambda().eq(DeliverDeliver::getId, deliver.getId()).set(DeliverDeliver::getStatus, DELIVER_STATUS_STOP.getValue()));
                throw new BusinessException("投放时间过期");
            }

            Date delayDate = Date.from(sms_deliver.getDeliverTime().atZone(ZoneId.systemDefault()).toInstant());
            beforeDeliverSmsDeliver(sms_deliver, param, deliver, true, delayDate);
        } else if (StrUtil.equals("review_success", action) && sms_deliver.getIsDelay().equals(0)) {
            boolean check_delay_result = deliverService.inCheckDelay(JSONArray.parseArray(sms_deliver.getAntiDisturTimes()));
            if (check_delay_result) {
                JSONObject option_deliver_time = JSON.parseObject(sms_deliver.getOptionDeliverTime());
                if (!option_deliver_time.isEmpty()) {
                    String hour = option_deliver_time.getString("hour");
                    String minute = option_deliver_time.getString("minute");
                    LocalDate date = LocalDate.now().plusDays(1);
                    LocalTime time = LocalTime.of(Integer.parseInt(hour), Integer.parseInt(minute));
                    LocalDateTime deliver_time = LocalDateTime.of(date, time);
                    Date delayDate = Date.from(deliver_time.atZone(ZoneId.systemDefault()).toInstant());
                    beforeDeliverSmsDeliver(sms_deliver, param, deliver, true, delayDate);
                } else {
                    deliverDeliverMapper.update(null, new UpdateWrapper<DeliverDeliver>().lambda().eq(DeliverDeliver::getId, deliver.getId()).set(DeliverDeliver::getStatus, DELIVER_STATUS_STOP.getValue()));
                }
            } else {
                //立即投放
                beforeDeliverSmsDeliver(sms_deliver, param, deliver, true, null);
            }
        }
    }


    @Override
    public ServiceResult<?> smsDeliverUrge(String id, JSONObject param) {
        if (param.containsKey("length")) {
            if (param.getInteger("length") > 200) {
                return ServiceResult.fail(AppRequestErrorCode.PARAM_RANGE, ":template length is too long");
            }
        }
        if (param.containsKey("template")) {
            if (param.getString("template").length() > 200) {
                return ServiceResult.fail(AppRequestErrorCode.PARAM_RANGE, ":template length is too long");
            }
        }
        String sms_deliver_id = param.getString("sms_deliver_id");
        if (StrUtil.isEmpty(sms_deliver_id)) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "缺少短信投放id");
        }
        String sms_template_id = param.getString("sms_template_id");
        if (StrUtil.isEmpty(sms_template_id)) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, ":sms_template_id is required");
        }
        String orgId = SecurityContextHolder.getOrgId();
        DeliverSmsDeliver smsDeliver = originGetSmsDeliver(sms_deliver_id);
        //sms_deliver.is_mproject  项目经理投放 对应数据库无此字段
        List<String> member_ids;
        if (param.containsKey("member_ids")) {
            member_ids = param.getJSONArray("member_ids").toJavaList(String.class);
            if (CollectionUtils.isEmpty(member_ids)) {
                return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "缺少联系人");
            }
            member_ids = member_ids.stream().distinct().collect(Collectors.toList());
            member_ids = checkMemberDeliverStatus4Urge(member_ids, smsDeliver.getDeliverGroupId(), smsDeliver.getDeliverId(), DELIVER_TTYPE_SMS);
            smsDeliverUrgeByMemberIds(orgId, smsDeliver, id, member_ids, sms_template_id, param);
        } else {
            JSONObject filter_params = (JSONObject) param.getOrDefault("filter_params", new JSONObject());
            filter_params.put("s_type", Arrays.asList(SMSRECORD_S_TYPE_DELIVER.getNumber(), SMSRECORD_S_TYPE_AGAIN_DELIVER.getNumber()));
            //勾选全部催答不可选择"黑名单拦截"发送状态
            if (Objects.equals(SMSRECORD_STATUS_MEMBER_BLACKLIST.getValue(), param.getInteger("s_type"))) {
                throw new BusinessException(AppRequestErrorCode.PARAM_RANGE.toString(), "黑名单用户无法催答");
            }
            //免打扰拦截状态不可以催答
            Integer status = filter_params.getInteger("status");
            if (Objects.isNull(status)) {
                filter_params.put("status", Arrays.asList(SMSRECORD_STATUS_SENDING.getValue(), SMSRECORD_STATUS_SUCCESS.getValue(), SMSRECORD_STATUS_FAILED.getValue(), SMSRECORD_STATUS_BALANCE_SHORT.getValue()));
            } else if (status.equals(SMSRECORD_STATUS_DISTRUB.getValue())) {
                throw new BusinessException(AppRequestErrorCode.PARAM_RANGE.toString(), "免打扰拦截状态不可以催答");
            }
            List<String> exclude_member_ids = (List<String>) param.getOrDefault("exclude_member_ids", Collections.emptyList());
            smsDeliverRecordMembers(smsDeliver, filter_params, exclude_member_ids, id);
            //由于此处member_ids没有值，所以一下方法省略
            //smsDeliverUrgeByMemberIds(orgId, smsDeliver, id, Collections.emptyList(), sms_template_id, param);
        }
        Map<String, String> res = new HashMap(2);
        res.put("id", id);
        return ServiceResult.success(res);
    }

    /**
     * 检查联系人的投放状态
     *
     * @param member_ids
     * @param deliverGroupId
     * @param deliverId
     * @param deliver_type   投放类型
     * @return
     */
    public List<String> checkMemberDeliverStatus4Urge(List<String> member_ids, String deliverGroupId, String
            deliverId, DeliverTtypeEnum deliver_type) {
        LambdaQueryWrapper<DeliverSmsRecord> queryWrapper = new LambdaQueryWrapper<>();
        //这些状态容许催答
        queryWrapper.in(DeliverSmsRecord::getStatus, SMSRecordStatus.SMSRECORD_STATUS_SENDING.getNumber(), SMSRecordStatus.SMSRECORD_STATUS_SUCCESS.getNumber(), SMSRecordStatus.SMSRECORD_STATUS_FAILED.getNumber(), SMSRECORD_STATUS_BALANCE_SHORT.getValue());
        //s_type 为投放或二次投放
        queryWrapper.in(DeliverSmsRecord::getSType, SMSRecordSType.SMSRECORD_S_TYPE_DELIVER.getNumber(), SMSRecordSType.SMSRECORD_S_TYPE_AGAIN_DELIVER.getNumber());
        if (member_ids.size() == 1) {
            queryWrapper.eq(DeliverSmsRecord::getMemberId, member_ids.get(0));
            queryWrapper.eq(DeliverSmsRecord::getDeliverId, deliverId);
            if (StrUtil.isNotEmpty(deliverGroupId)) {
                queryWrapper.eq(DeliverSmsRecord::getDeliverGroupId, deliverGroupId);
            }
            DeliverSmsRecord record = deliverSmsRecordMapper.selectOne(queryWrapper);
            return Objects.nonNull(record) ? member_ids : Collections.emptyList();
        }
        //先查出对应的所有可以催答的投放member_ids，之后取交集
        queryWrapper.eq(DeliverSmsRecord::getDeliverId, deliverId);
        if (StrUtil.isNotEmpty(deliverGroupId)) {
            queryWrapper.eq(DeliverSmsRecord::getDeliverGroupId, deliverGroupId);
        }
        List<String> db_member_id_set = deliverSmsRecordMapper.selectList(queryWrapper).stream().map(DeliverSmsRecord::getMemberId).distinct().collect(Collectors.toList());
        return (List<String>) CollectionUtils.intersection(db_member_id_set, member_ids);
    }

    @Override
    public ServiceResult<?> smsDelivers(SmsDeliversParam param) {
        String deliverName = param.getDeliverName();
        if (StrUtil.isEmpty(deliverName)) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "投放名称参数缺失");
        }
        if (deliverName.length() > 30) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_RANGE, "投放名称超出长度限制");
        }
        OrgInfoDto organization = userGrpcClient.getOrganization(SecurityContextHolder.getOrgId());
        boolean isCheck = Optional.ofNullable(organization.getIsDeliverCheck()).orElse(false);
        if (isCheck != (param.getIsCheck() == 1)) {
            return ServiceResult.fail(ValidationErrorCodeEnum.ORG_DELIVER_CHECK_CHANGED.getCode(), ValidationErrorCodeEnum.ORG_DELIVER_CHECK_CHANGED.getMsg());
        }
        String deliverId = createSmsDeliver(param);
        if (Objects.nonNull(param.getIsDelay()) && param.getIsDelay() == 1 && Objects.isNull(param.getDeliverTime())) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "投放定时时间参数缺失");
        }
        if (isCheck) {
            //保存之后投放状态改为 “未投放”
            deliverService.updateDeliver(deliverId);
        }
        Map<String, String> res = new HashMap<>(2);
        res.put("id", deliverId);
        return ServiceResult.success(res);
    }

    @Override
    public String createSmsDeliver(SmsDeliversParam param) {
        String orgId = SecurityContextHolder.getOrgId();
        Integer surveySubmitType = Optional.ofNullable(param.getSurveySubmitType()).orElse(SurverySubmitTyeEnum.LIMITED_ONE_SURVERY_SUBMINT_TYPE.getIndex());
        if (surveySubmitType.equals(SurverySubmitTyeEnum.LIMITED_ONE_IN_DELIVER_GROUP_SUBMINT_TYPE.getIndex())) {
            emailDeliverService.originGetDeliverGroup(param.getDeliverGid());
        }
        DeliverDeliver deliver;
        if (param instanceof SmsDeliversParamAgain) {
            SmsDeliversParamAgain again = (SmsDeliversParamAgain) param;
            deliver = emailDeliverService.createDeliver(orgId, param.getDeliverId(), param.getDeliverName(), param.getDeliverTime(), DELIVER_TTYPE_SMS.getValue(), DeliverChannel.DELIVER_CHANNEL_SMS.getNumber(), again.getAwardUseType(), again.getAwardId());
        } else {
            deliver = emailDeliverService.createDeliver(orgId, param.getDeliverId(), param.getDeliverName(), param.getDeliverTime(), DELIVER_TTYPE_SMS.getValue(), DeliverChannel.DELIVER_CHANNEL_SMS.getNumber(), DELIVER_AWARD_USE_TYPE_UNUSE.getNumber(), null);
        }
        String deliverId = deliver.getId();

        deliverService.setDeliverRespondentEnableRedis(deliverId, true);

        //# 创建问卷投放，并发布消息到qdes.project.updated进行项目更新
        emailDeliverService.deliverCreateSurveydeliver(orgId, param.getSurveyId(), deliverId);
        if (SurverySubmitTyeEnum.LIMITED_ONE_SURVERY_SUBMINT_TYPE.getIndex().equals(surveySubmitType)) {
            String deliverGroupId = emailDeliverService.createDeliverGroup(orgId, param.getSurveyId(), Collections.singletonList(deliver.getId()));
            log.info("创建投放组成功：dliver_g_id={}", deliverGroupId);
            param.setDeliverGid(deliverGroupId);
        } else if (SurverySubmitTyeEnum.LIMITED_ONE_IN_DELIVER_GROUP_SUBMINT_TYPE.getIndex().equals(surveySubmitType)) {
            emailDeliverService.addDeliverToGroup(deliverId, param.getSurveyId(), param.getDeliverGid());
        }
        String template;
        if (StrUtil.isNotEmpty(param.getTemplateId())) {
            MessageCenterTemplate messageCenterTemplate = messageCenterClient.getMessageTemplateById(param.getTemplateId());
            if (Objects.isNull(messageCenterTemplate)) {
                throw new BusinessException(String.format("template[%s] Not Found", param.getTemplateId()));
            }
            template = messageCenterTemplate.getTemplate();
        } else {
            template = "";
        }
        Map<String, Object> signMap = new HashMap<>(4);
        signMap.put("template", template);
        String hashcode = SignUtil.genSign(signMap, deliverService.getDeliverSecret());
        originCreateSmsDeliver(orgId, param, deliverId, hashcode);
        deliverService.doDefaultDeliverNameSeq(param.getDeliverName(), param.getSurveyId(), DELIVER_TTYPE_SMS.getValue());
        return deliver.getId();
    }

    private void originCreateSmsDeliver(String orgId, SmsDeliversParam param, String deliverId, String hashcode) {
        DeliverSmsDeliver smsDeliver = new DeliverSmsDeliver();
        smsDeliver.setOrgId(orgId);
        smsDeliver.setSurveyId(param.getSurveyId());
        smsDeliver.setDeliverId(deliverId);
        smsDeliver.setDeliverGroupId(param.getDeliverGid());
        smsDeliver.setCheckSubmit(param.getCheckSubmit());
        smsDeliver.setHashcode(hashcode);
        smsDeliver.setIsDelay(Optional.ofNullable(param.getIsDelay()).orElse(0));
        smsDeliver.setIsCheck(Optional.ofNullable(param.getIsCheck()).orElse(0));
        smsDeliver.setDeliverTime(param.getDeliverTime());
        smsDeliver.setAntiDisturTimes(Optional.ofNullable(param.getAntiDisturTimes()).map(JSON::toJSONString).orElse("[]"));
        if (param instanceof SmsDeliversParamAgain) {
            SmsDeliversParamAgain again = (SmsDeliversParamAgain) param;
            smsDeliver.setSmsTemplateId(again.getSmsTemplateId());
            smsDeliver.setTemplate(again.getTemplate());
            smsDeliver.setLength(again.getLength());
        }
        //设置默认值
        smsDeliver.setOptionDeliverTime("{}");
        smsDeliver.setFilterParams("{}");
        smsDeliver.setMprojectMobile("[]");
        smsDeliver.setMobileList("[]");
        smsDeliver.setNoDisturbMemberIdList("[]");
        log.info("新增短信投放参数{}", smsDeliver);
        baseMapper.insert(smsDeliver);
        String smsDeliverId = smsDeliver.getId();
        List<String> memberIds = param.getMemberIdlist();
        batchInsertSmsDeliverMemberId(smsDeliverId, memberIds);
    }

    private void batchInsertSmsDeliverMemberId(String smsDeliverId, List<String> member_id_list) {
        if (CollectionUtils.isNotEmpty(member_id_list)) {
            List<DeliverSmsDeliverMemberId> list = member_id_list.stream().map(itd -> {
                DeliverSmsDeliverMemberId insertObj = new DeliverSmsDeliverMemberId();
                insertObj.setMemberId(itd);
                insertObj.setSmsdeliverId(smsDeliverId);
                return insertObj;
            }).collect(Collectors.toList());

            if (!list.isEmpty()) {
                smsDeliverMemberIdMapper.insertBatchSomeColumn(list);
            }
        }
    }

    /**
     * 根据传递的联系人列表进行催答
     *
     * @param orgId
     * @param smsDeliver
     * @param id
     * @param member_ids
     * @param sms_template_id
     * @param sms_info
     */
    private void smsDeliverUrgeByMemberIds(String orgId, DeliverSmsDeliver smsDeliver, String id, List<String> member_ids, String sms_template_id, JSONObject sms_info) {
        if (member_ids.size() == 1) {
            if (emailDeliverService.checkMemberDeliverUrgeStatus(member_ids.get(0), smsDeliver.getDeliverGroupId(), smsDeliver.getDeliverId())) {
                throw new BusinessException(String.valueOf(STATUS_CHANGED.getCode()), "当前用户已经提交问卷，无法催答");
            }
            if (!checkMemberSmsContent(smsDeliver.getId(), member_ids.get(0))) {
                throw new BusinessException(String.valueOf(STATUS_CHANGED.getCode()), "当前用户短信内容为空，无法催答");
            }
        }
        List<String> urge_member_ids = new ArrayList<>();
        member_ids.forEach(v -> {
            if (!emailDeliverService.checkMemberDeliverUrgeStatus(v, smsDeliver.getDeliverGroupId(), smsDeliver.getDeliverId())) {
                urge_member_ids.add(v);
            }
        });
        if (urge_member_ids.isEmpty()) {
            throw new BusinessException(String.valueOf(STATUS_CHANGED.getCode()), "没有可催答的联系人");
        }
        //创建催答记录
        DeliverSmsDeliverUrge smsDeliverUrge = new DeliverSmsDeliverUrge();
        smsDeliverUrge.setSmsDeliverId(smsDeliver.getId());
        smsDeliverUrge.setMemberIds(JSON.toJSONString(member_ids));
        smsDeliverUrge.setSmsTemplateId(smsDeliver.getSmsTemplateId());
        smsDeliverUrge.setOrgId(orgId);
        deliverSmsDeliverUrgeMapper.insert(smsDeliverUrge);
        //进行催答
        sms_info.put("member_id_list", urge_member_ids);
        sms_info.put("s_type", SMSRECORD_S_TYPE_URGE.getNumber());
        sms_info.put("sms_template_id", sms_template_id);
        sms_info.put("deliver_urge_id", smsDeliverUrge.getId());
        deliverSmsDeliver(smsDeliver, sms_info, null, null);
    }

    /**
     * 检查催答的联系的短信内容是否为空
     *
     * @param sms_deliver_id
     * @param member_id
     * @return
     */
    private boolean checkMemberSmsContent(String sms_deliver_id, String member_id) {
        LambdaQueryWrapper<DeliverSmsRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverSmsRecord::getSmsDeliverId, sms_deliver_id);
        queryWrapper.eq(DeliverSmsRecord::getMemberId, member_id);
        queryWrapper.last("limit 1");
        DeliverSmsRecord deliverSmsRecord = deliverSmsRecordMapper.selectOne(queryWrapper);
        return Objects.nonNull(deliverSmsRecord) && StrUtil.isNotEmpty(deliverSmsRecord.getContent());
    }


    private DeliverSmsDeliver originGetSmsDeliver(String smsDeliverId) {
        DeliverSmsDeliver smsDeliver = baseMapper.selectById(smsDeliverId);
        if (Objects.isNull(smsDeliver)) {
            throw new BusinessException(String.valueOf(AppResourceErrorCode.NOT_FOUND), String.format("SmsDeliver[id=%s] not found", smsDeliverId));
        }
        return smsDeliver;
    }

    @Override
    public void smsDeliverExport(JSONObject param, HttpServletResponse response, DeliverSmsDeliver smsDeliver, DeliverDeliver deliver) {
        Integer check_submit = smsDeliver.getCheckSubmit();
        String project_id = param.getString("project_id");
        List<JSONObject> record_list;
        Map<String, List<Integer>> member_maps = new HashMap<>();
        if (param.containsKey("member_ids")) {
            List<String> member_ids = param.getJSONArray("member_ids").toJavaList(String.class);
            if (CollectionUtils.isEmpty(member_ids)) {
                throw new BusinessException("缺少联系人member_ids");
            }
            record_list = getEmailRecordBySelect(smsDeliver, project_id, member_ids, member_maps);
        } else {
            List<String> exclude_member_ids = null;
            if (param.containsKey("exclude_member_ids")) {
                exclude_member_ids = param.getJSONArray("exclude_member_ids").toJavaList(String.class);
            }

            JSONObject filter_params = param.getJSONObject("filter_params");
            record_list = getSmsRecordByFilterParams(smsDeliver, filter_params, exclude_member_ids, project_id, member_maps);
        }
        boolean display_contact;
        if (!member_maps.isEmpty()) {
            display_contact = memberGrpcClient.checkDisplayRangePermission(SecurityContextHolder.getOrgId(), SecurityContextHolder.getUserId(), new ArrayList<>(member_maps.keySet()).get(0));
        } else {
            display_contact = true;
        }
        //导出
        String ossUrl = exportExcelSmsRecordByIds(record_list, member_maps, display_contact, check_submit, response);
        log.info("短信投放导出文件路径={}", ossUrl);
    }

    @Override
    public ServiceResult<?> editSmsDelivers(String id, JSONObject param) {
        DeliverSmsDeliver smsDeliver = baseMapper.selectById(id);
        DeliverDeliver deliver = emailDeliverService.getDeliver(smsDeliver.getDeliverId());
        if (Objects.equals(smsDeliver.getIsCheck(), 1)) {
            //增加未投放可以编辑
            if (!DeliverStatusEnum.getDeliverCheck2Value().contains(deliver.getStatus())) {
                return ServiceResult.fail(STATUS_CHANGED, "投放状态不支持编辑");
            }
        } else {
            if (!Objects.equals(DELIVER_STATUS_STOP.getValue(), deliver.getStatus())) {
                return ServiceResult.fail(STATUS_CHANGED, "投放状态不支持编辑");
            }
        }
        return editSmsDeliver(smsDeliver, param);
    }

    private ServiceResult<?> editSmsDeliver(DeliverSmsDeliver smsDeliver, JSONObject param) {
        String orgId = SecurityContextHolder.getOrgId();
        if (Objects.equals(smsDeliver.getIsCheck(), 0) && Objects.equals(smsDeliver.getIsDelay(), 1) && Objects.equals(param.get("is_delay"), 0)) {
            param.put("_sign", true);
        }
        param.put("is_check", param.getInteger("is_check") == 1);
        param.put("is_delay", param.getInteger("is_delay") == 1);
        //发送问卷时需要携带唯一链接，在start接口进行修改
        Integer survey_submit_type = (Integer) param.getOrDefault("survey_submit_type", LIMITED_ONE_SURVERY_SUBMINT_TYPE.getIndex());
        if (survey_submit_type.equals(LIMITED_ONE_IN_DELIVER_GROUP_SUBMINT_TYPE.getIndex())) {
            DeliverDeliverGroup deliverDeliverGroup = deliverDeliverGroupMapper.selectById(smsDeliver.getDeliverGroupId());
            if (Objects.isNull(deliverDeliverGroup)) {
                return ServiceResult.fail(-1, "投放组不存在");
            }
        }
        param.put("deliver_id", smsDeliver.getDeliverId());
        String survey_id = param.getString("survey_id");
        String deliverId = smsDeliver.getDeliverId();
        emailDeliverService.delDeliverFromGroup(smsDeliver.getDeliverId(), survey_id);
        if (survey_submit_type.equals(LIMITED_ONE_SURVERY_SUBMINT_TYPE.getIndex())) {
            String deliverGroupId = emailDeliverService.createDeliverGroup(orgId, survey_id, Collections.singletonList(deliverId));
            log.info("创建投放组成功");
            param.put("deliver_group_id", deliverGroupId);
        } else if (survey_submit_type.equals(LIMITED_ONE_IN_DELIVER_GROUP_SUBMINT_TYPE.getIndex())) {
            emailDeliverService.addDeliverToGroup(deliverId, survey_id, smsDeliver.getDeliverGroupId());
            param.put("deliver_group_id", param.getString("deliver_g_id"));
        } else {
            param.put("deliver_group_id", null);
        }
        //编辑时清空之前的 member_id_list，避免投放时联系人列表是未更新的。
        param.put("member_id_list", new ArrayList<>());
        originUpdateSmsDeliver(smsDeliver, param);
        updateSmsDeliver(smsDeliver, param);
        JSONObject ret = new JSONObject();
        ret.put("id", deliverId);
        ret.put("status", true);
        return ServiceResult.success(ret);
    }

    private ServiceResult<?> updateSmsDeliver(DeliverSmsDeliver smsDeliver, JSONObject param) {
        if (!param.isEmpty()) {
            JSONObject deliver_params = new JSONObject();
            param.forEach((key, value) -> {
                if (key.startsWith("_deliver_")) {
                    String real_key = StrUtil.removePrefix(key, "_deliver_");
                    deliver_params.put(real_key, value);
                }
            });
            if (!deliver_params.isEmpty()) {
                //解决定时任务，多次更新触发多个定时任务的问题, 时间戳取到微秒
                long version = System.currentTimeMillis() * 1000;
                deliver_params.put("version", version);
                DeliverDeliver updateDeliver = JSON.toJavaObject(deliver_params, DeliverDeliver.class);
                updateDeliver.setId(smsDeliver.getDeliverId());
                deliverDeliverMapper.updateById(updateDeliver);
            }

            //更新投放设置（部分） 和 更新联系人都会调用这个函数 判断filter_params 以确定是不是需要更新投放联系人列表的put
            List<String> not_distrub_member_list = new ArrayList<>();
            Boolean isUpload = (Boolean) param.get("is_upload");
            if (CollUtil.isNotEmpty(param.getJSONObject("filter_params"))) {
                if (param.containsKey("not_distrub_member")) {
                    JSONArray notDistrubMembers = param.getJSONArray("not_distrub_member");
                    log.info("短信投放获取到的免打扰联系人列表----->>>>>{}", notDistrubMembers);
                    if (!notDistrubMembers.isEmpty()) {
                        not_distrub_member_list = notDistrubMembers.stream().map(String::valueOf).collect(Collectors.toList());
                        param.put("no_disturb_member_id_list", not_distrub_member_list);
                    }
                }
                if (Objects.isNull(isUpload) || !isUpload) {
                    //提前过滤掉 免打扰的id列表，为了在编辑投放时，显示投放联系人时分页查询
                    JSONObject filter_params = new JSONObject();
                    //加入免打扰联系人ids
                    filter_params.putAll(param.getJSONObject("filter_params"));
                    filter_params.put("not_distrub_member", not_distrub_member_list);
                    //增加过滤黑名单
                    Map<String, Object> filter = new HashMap<>();
                    filter.put("member_delivery_status", 1);
                    filter_params.put("filter", filter);
                    filter_params.put("push_type", "mobile");

                    //# 是否是项目经理投放，项目投放暂无免打扰 无此字段

                    Integer superRole = SecurityContextHolder.getToken().getSuperRole();
                    Integer isSenior = SecurityContextHolder.getToken().getIsSenior();
                    Map<String, Object> kwargs = new HashMap<>(8);
                    kwargs.put("org_id", SecurityContextHolder.getOrgId());
                    kwargs.put("user_id", SecurityContextHolder.getUserId());
                    kwargs.put("super_admin", superRole == 1);
                    kwargs.put("senior_admin", isSenior == 1);
                    List<String> member_ids = memberGrpcClient.listMembersByFilterParam(kwargs, filter_params.toJSONString());
                    param.put("member_id_list", member_ids);
                }
            }
            Map<String, Object> signMap = new HashMap<>(4);
            signMap.put("template", Optional.ofNullable(param.getString("template")).orElse(smsDeliver.getTemplate()));
            String hashcode = SignUtil.genSign(signMap, deliverService.getDeliverSecret());
            param.put("hashcode", hashcode);
            originUpdateSmsDeliver(smsDeliver, param);
            /*if (Objects.nonNull(isUpload) && !isUpload) {
                私有部署时不开启
                createOrUpdatePreCharge();
            }*/
            if (param.containsKey("_sign") && param.getBooleanValue("_sign")) {
                // 这里会不会有一级缓存？查到的不是最新？
                smsDeliver = baseMapper.selectById(smsDeliver.getId());
                // 批量发送, 批量创建record
                return beforeDeliverSmsDeliver(smsDeliver, param, null, null, null);
            }
            Map res = new HashMap(2);
            res.put("id", smsDeliver.getId());
            return ServiceResult.success(res);
        }
        return ServiceResult.success();
    }


    private ServiceResult<?> beforeDeliverSmsDeliver(DeliverSmsDeliver smsDeliver, JSONObject param, DeliverDeliver deliver, Boolean deliver_check, Date delayDate) {
        String deliverId = smsDeliver.getDeliverId();
        Integer isUpload = smsDeliver.getIsUpload();
        param.put("is_upload", isUpload);
        param.put("is_sync_mem", smsDeliver.getIsSyncMem());
        String filterParams = smsDeliver.getFilterParams();
        param.put("filter_params", filterParams);
        Map<String, Object> params = new HashMap<>(4);
        params.put("length", smsDeliver.getLength());
        params.put("template", smsDeliver.getTemplate());
        param.put("params", params);
        if (Objects.equals(1, isUpload)) {
            // 处理随机投放
            JSONObject randomSampling = param.getJSONObject("random_sampling");
            param.put("primary_key", "mobile");
            //同步名单联系人
            if (Objects.equals(1, param.get("is_sync_mem"))) {
                List<String> memberIdList = memberGrpcClient.importDeliverMember(SecurityContextHolder.getOrgId(), deliverId, "mobile");
                if (Objects.nonNull(randomSampling) && !randomSampling.isEmpty()) {
                    int size = memberIdList.size();
                    // 按数量或者比例 应该随机得到的联系人数量
                    ServiceResult<Integer> selectNumsResult = emailDeliverService.dealRandomSampling(randomSampling, size);
                    if (!selectNumsResult.isSuccess()) {
                        return ServiceResult.fail(selectNumsResult.getMsg());
                    }
                    Integer selectNum = selectNumsResult.getData();
                    log.info("member.utils random_sampling----->select:{}-----all:{}", selectNum, size);
                    memberIdList = RandomUtil.randomEleList(memberIdList, selectNum);
                    if (log.isInfoEnabled()) {
                        log.info("随机的联系人数量 {} id 是{}", selectNum, memberIdList);
                    }
                }
                param.put("member_id_list", memberIdList);
                //member_id_list 拆表，直接调用model_utils中的方法，关联表不能自动创建数据
                originUpdateSmsDeliver(smsDeliver, param);
                /*if (Objects.nonNull(isUpload) && !isUpload) {
                    私有部署时不开启
                    createOrUpdatePreCharge();
                }*/
            } else {
                // 下载投放上传的联系人excel文件
                //String filePath = ossService.getFilePrefix() + "deliver_member/" + deliverId.trim() + "/投放名单.xlsx";
                String filePath = storageService.getPropertiesValueBy(null, "base-path") + "deliver_member/" + deliverId.trim() + "/投放名单.xlsx";
                log.info("读取文件:{}", filePath);
                List<MemberDeliverDataByMobile> members;
                try {
                    members = parseInputStream(filePath);
                } catch (Exception e) {
                    log.error("[deliver] 获取oss文件流失败:url {}", e.getMessage());
                    return ServiceResult.fail(e.getMessage());
                }
                List<String> mobileList = members.stream().map(MemberDeliverDataByMobile::getPhone).collect(Collectors.toList());
                Map<String, List<String>> smsContacts = new HashMap<>();
                members.forEach(v -> smsContacts.put(v.getPhone(), Arrays.asList(v.getName(), v.getOrganization())));
                param.put("sms_contacts_message", smsContacts);
                int size = mobileList.size();
                // 按数量或者比例 应该随机得到的联系人数量
                ServiceResult<Integer> selectNumsResult = emailDeliverService.dealRandomSampling(randomSampling, size);
                if (!selectNumsResult.isSuccess()) {
                    return ServiceResult.fail(selectNumsResult.getMsg());
                }
                Integer selectNum = selectNumsResult.getData();
                mobileList = RandomUtil.randomEleList(mobileList, selectNum);
                param.put("mobile_list", mobileList);
                oldUpdateSmsDeliver(smsDeliver.getDeliverId(), param);
                /*if (Objects.nonNull(isUpload) && !isUpload) {
                    私有部署时不开启
                    createOrUpdatePreCharge();
                }*/
            }
        }
        return deliverSmsDeliver(smsDeliver, param, deliver_check, delayDate);
    }

    public List<MemberDeliverDataByMobile> parseInputStream(String excelFilePath) {
        DynamicEasyExcelImportUtil.EasyExcelListener<MemberDeliverDataByMobile> excelListener = new DynamicEasyExcelImportUtil.EasyExcelListener<>();
        //InputStream is = ossService.downloadFile(excelFilePath);
        //InputStream is = storageService.downloadFile(excelFilePath);
        InputStream is = new ByteArrayInputStream(storageService.downloadByUrl(storageService.getPropertiesValueBy(null, "domain") + excelFilePath).bytes());
        // 读取数据
        EasyExcel.read(is, MemberDeliverDataByMobile.class, excelListener).sheet().doRead();
        if (org.springframework.util.CollectionUtils.isEmpty(excelListener.getResult())) {
            return Collections.emptyList();
        }

        return new ArrayList<>(excelListener.getResult());
    }

    private ServiceResult<?> deliverSmsDeliver(DeliverSmsDeliver smsDeliver, JSONObject param, Boolean deliverCheck, Date delayDate) {
        Integer sType = Optional.ofNullable((Integer) param.get("s_type")).orElse(SMSRECORD_S_TYPE_DELIVER.getNumber());
        //是否为非催答(投放发送)
        //true代表正常投放，false代表催答
        boolean isNoUrge = !sType.equals(SMSRECORD_S_TYPE_URGE.getNumber());
        LambdaQueryWrapper<DeliverSmsDeliverMemberId> qwrap = new LambdaQueryWrapper<>();
        qwrap.select(DeliverSmsDeliverMemberId::getMemberId);
        qwrap.eq(DeliverSmsDeliverMemberId::getSmsdeliverId, smsDeliver.getId());
        List<DeliverSmsDeliverMemberId> objList = smsDeliverMemberIdMapper.selectList(qwrap);
        if (objList.size() > 0) {
            List<String> ids = objList.stream().map(DeliverSmsDeliverMemberId::getMemberId).filter(StrUtil::isNotEmpty).distinct().collect(Collectors.toList());
            smsDeliver.setMemberIdlist(ids);
        }
        Project project = qdesGrpcClient.getProject(smsDeliver.getSurveyId());
        String projectName = project.getTitle();
        projectName = projectName.length() > 10 ? projectName.substring(0, 10) : projectName;
        String ques_name = emailDeliverService.getQdesName(smsDeliver.getSurveyId(), project.getStructId());
        ques_name = ques_name.length() > 10 ? ques_name.substring(0, 10) : ques_name;
        String orgId = SecurityContextHolder.getOrgId();
        String systematic_name = emailDeliverService.getSystemName(orgId);
        systematic_name = systematic_name.length() > 15 ? systematic_name.substring(0, 15) : systematic_name;
        DeliverDeliver deliver = emailDeliverService.getDeliver(smsDeliver.getDeliverId());
        if (isNoUrge) {
            //如果当前投放是被修改过，导致version不一致直接结束投放
            String paramVersion = param.getString("version");
            String deliverVersion = deliver.getVersion().toString();
            if (StrUtil.isNotBlank(paramVersion) && StrUtil.isNotBlank(deliverVersion)) {
                if (!StrUtil.equals(paramVersion, deliverVersion)) {
                    throw new BusinessException("当前投放version不一致");
                }
            }
        } else {
            //如果params 中有短信模板id 则用params中的
            String sms_template_id = param.getString("sms_template_id");
            if (StringUtils.isNotEmpty(sms_template_id)) {
                smsDeliver.setSmsTemplateId(sms_template_id);
            }
        }
        //sms_deliver.is_mproject  项目经理投放 对应数据库无此字段
        HashMap<String, String> kwargs = new HashMap<>();
        if (deliver.getAwardUseType() == DELIVER_AWARD_USE_TYPE_USE.getNumber()) {
            kwargs.put("awardId", deliver.getAwardId());
        }

        Integer status = deliver.getStatus();
        Boolean flag = null;
        if (isNoUrge) {
            if (Objects.nonNull(deliverCheck) && deliverCheck) {
                if (!DeliverStatusEnum.getDeliverCheck1Value().contains(status)) {
                    return ServiceResult.fail(-1, "当前投放状态错误");
                }
            }
            Integer isUpload = param.getInteger("is_upload");
            flag = (Objects.isNull(isUpload) || isUpload == 0) || Objects.equals(1, param.get("is_sync_mem"));
        } else {
            if (DeliverStatusEnum.getDeliverCheck3Value().contains(status)) {
                return ServiceResult.fail(-1, "当前投放状态错误");
            }
            if (param.containsKey("member_id_list")) {
                smsDeliver.setMemberIdlist((List<String>) param.get("member_id_list"));
            }
        }
        if (CollectionUtils.isEmpty(smsDeliver.getMemberIdlist())) {
            log.info("短信投放符合条件联系人的数量为0");
            return ServiceResult.fail(-1, "短信投放符合条件联系人的数量为0");
        }
        log.info("短信投放的联系人的数量为:{}", smsDeliver.getMemberIdlist().size());
        String deliverUrgeId = param.getString("deliver_urge_id");
        Map<String, String> new_link_dict = new HashMap();
        //免打扰联系人id
        List<String> no_disturb_member_id_list;
        if (isNoUrge) {
            no_disturb_member_id_list = deliverService.getNodisturbMemberIdByDeliver(deliver.getId()).stream().distinct().collect(Collectors.toList());
        } else {
            //免打扰联系人id从投放联系人中去除
            no_disturb_member_id_list = JSONObject.parseArray(smsDeliver.getNoDisturbMemberIdList(), String.class);
            if (CollectionUtils.isNotEmpty(no_disturb_member_id_list)) {
                //取两者差集及非免打扰的联系人
                smsDeliver.setMemberIdlist((List<String>) CollectionUtils.subtract(smsDeliver.getMemberIdlist(), no_disturb_member_id_list));
            }
            LambdaQueryWrapper<DeliverSmsRecord> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DeliverSmsRecord::getSmsDeliverId, smsDeliver.getId());
            queryWrapper.eq(DeliverSmsRecord::getSType, SMSRECORD_S_TYPE_DELIVER.getNumber());
            List<DeliverSmsRecord> link_list = deliverSmsRecordMapper.selectList(queryWrapper);
            link_list.forEach(v -> {
                String surveylink = JSONObject.parseObject(v.getParams()).getString("surveylink");
                if (StrUtil.isNotEmpty(surveylink) && ReUtil.isMatch(URL_REGEX, surveylink)) {
                    new_link_dict.put(v.getMemberId(), surveylink);
                }
            });
        }
        log.info("短信投放免打扰联系人的数量为:{}", no_disturb_member_id_list.size());

        //改成mq消息处理
        log.info("短信投放发送mq消息start");

        //改成mq处理,比如5000一个mq消息，这样可以几台机器一起消费，执行投放过程
        List<List<String>> list = !isNoUrge || flag ? ListUtil.partition(smsDeliver.getMemberIdlist(), DELIVER_MQ_BATCH_SIZE) : ListUtil.partition(JSONArray.parseArray(smsDeliver.getMobileList()).toJavaList(String.class), DELIVER_MQ_BATCH_SIZE);
        log.info("短信投放{}发送{}条mq消息,每批次{}", deliver.getId(), list.size(), DELIVER_MQ_BATCH_SIZE);
        //生成签名的value不能为null
        kwargs.put("deliver_g_id", Optional.ofNullable(smsDeliver.getDeliverGroupId()).orElse(""));
        for (List<String> subList : list) {
            SmsDeliverMessageDto dto = new SmsDeliverMessageDto();
            dto.setId(smsDeliver.getId());
            dto.setOrgId(smsDeliver.getOrgId());
            dto.setSurveyId(smsDeliver.getSurveyId());
            dto.setDeliverId(smsDeliver.getDeliverId());
            dto.setTemplate(smsDeliver.getTemplate());
            dto.setCheckSubmit(smsDeliver.getCheckSubmit());
            dto.setDeliverGroupId(smsDeliver.getDeliverGroupId());
            dto.setKwargs(kwargs);
            dto.setProjectName(projectName);
            dto.setNoDisturbMemberIdlist(no_disturb_member_id_list);
            dto.setMsgTotal(list.size());
            dto.setSystemName(systematic_name);
            dto.setQuesName(ques_name);
            dto.setSType(sType);
            dto.setFlag(flag);
            if (!isNoUrge || flag) {
                dto.setMemberIdlist(subList);
            } else {
                dto.setMobileList(subList);
            }
            dto.setSmsContacts((Map<String, List<String>>) param.get("sms_contacts_message"));
            if (!isNoUrge) {
                dto.setNewLinkDict(new_link_dict);
                dto.setDeliverUrgeId(deliverUrgeId);
                dto.setTemplate(param.getString("template"));
            }
            dto.setVersion(deliver.getVersion());
            //发送mq消息
            sendDeliverMsg(dto, delayDate);
        }
        log.info("短信投放发送mq消息end");
        return ServiceResult.success();
    }

    private void sendDeliverMsg(SmsDeliverMessageDto dto, Date delayDate) {
        if (Objects.isNull(delayDate)) {
            //立即投放
            deliverMessageSendService.smsDeliverSend(dto);
        } else {
            //延迟投放
            deliverMessageSendService.smsDeliverSend(dto, delayDate);
        }
    }

    private DeliverSmsDeliver retryQuerySmsDeliver(String id) {
        //表示哪些异常需要重试
        //key一定要为Throwable异常的子类    Class<? extends Throwable>
        //value为true表示需要重试
        Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
        // 1 添加异常的处理结果 true为需要重试 false为不需要重试
        exceptionMap.put(BusinessException.class, true);

        // 2 构建重试模板实例
        RetryTemplate retryTemplate = new RetryTemplate();

        // 3 设置重试回退操作策略  设置重试间隔时间
        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        backOffPolicy.setInitialInterval(1000);
        backOffPolicy.setMultiplier(1.5);
        backOffPolicy.setMaxInterval(60000);

        // 4 设置重试策略  设置重试次数 设置异常处理结果
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(3, exceptionMap);

        //5 重试模板添加重试策略 添加回退操作策略
        retryTemplate.setRetryPolicy(retryPolicy);
        retryTemplate.setBackOffPolicy(backOffPolicy);

        // 6 调用方法
        return retryTemplate.execute(
                // RetryCallback 重试回调方法
                retryCallback -> querySmsDeliverAndMemberIdList(id),
                // RecoveryCallback 异常回调方法
                recoveryCallback -> {
                    Throwable throwable = recoveryCallback.getLastThrowable();
                    log.error("retryQuerySmsDeliver失败, id: {}, retryCount: {}", id, recoveryCallback.getRetryCount(), throwable);
                    throw new BusinessException("公众号投放缺少关键参数member_id_list和mp_template_id，无法执行异步任务发送消息");
                });
    }

    private DeliverSmsDeliver querySmsDeliverAndMemberIdList(String id) {
        DeliverSmsDeliver smsDeliver = baseMapper.selectById(id);
        if (StrUtil.isEmpty(smsDeliver.getSmsTemplateId())) {
            throw new BusinessException("短信投放更新还没结束，稍后重试查询1");
        }

        LambdaQueryWrapper<DeliverSmsDeliverMemberId> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(DeliverSmsDeliverMemberId::getMemberId);
        wrapper.eq(DeliverSmsDeliverMemberId::getSmsdeliverId, smsDeliver.getId());
        List<DeliverSmsDeliverMemberId> objList = smsDeliverMemberIdMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(objList)) {
            throw new BusinessException("短信投放更新还没结束，稍后重试查询2");
        }

        List<String> ids = objList.stream().map(DeliverSmsDeliverMemberId::getMemberId).filter(StrUtil::isNotEmpty).distinct().collect(Collectors.toList());
        smsDeliver.setMemberIdlist(ids);
        return smsDeliver;
    }

    private void oldUpdateSmsDeliver(String smsDeliverId, JSONObject param) {
        DeliverSmsDeliver deliver = JSON.toJavaObject(param, DeliverSmsDeliver.class);
        deliver.setId(smsDeliverId);
        baseMapper.updateById(deliver);
    }

    private void originUpdateSmsDeliver(DeliverSmsDeliver smsDeliver, JSONObject param) {
        String smsDeliverId = smsDeliver.getId();
        if (param.containsKey("member_id_list")) {
            //如果参数中有member_id_list就先把原先数据删除
            LambdaQueryWrapper<DeliverSmsDeliverMemberId> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DeliverSmsDeliverMemberId::getSmsdeliverId, smsDeliverId);
            smsDeliverMemberIdMapper.delete(queryWrapper);
        }

        DeliverSmsDeliver deliver = JSON.toJavaObject(param, DeliverSmsDeliver.class);
        deliver.setId(smsDeliverId);
        baseMapper.updateById(deliver);

        List<String> member_id_list = (List<String>) param.get("member_id_list");
        batchInsertSmsDeliverMemberId(smsDeliverId, member_id_list);
    }

    /**
     * 根据投放发送记录id导出excel格式
     *
     * @param recordList
     * @param member_maps
     * @param display_contact
     * @param check_submit
     * @param response
     * @return
     */
    private String exportExcelSmsRecordByIds(List<JSONObject> recordList, Map<String, List<Integer>> member_maps, boolean display_contact, Integer check_submit, HttpServletResponse response) {
        if (CollectionUtils.isEmpty(recordList)) {
            return "没有数据";
        }
        List<List<List<String>>> head = new ArrayList<>();
        List<List<String>> headRowList = new ArrayList<>();

        List<List<List<Object>>> exportDataList = new ArrayList<>();
        List<List<Object>> rowList = new ArrayList<>();
        Set<String> member_id_set = new HashSet<>();
        for (JSONObject record : recordList) {
            String member_id = record.getString("member_id");
            if (member_id_set.contains(member_id)) {
                continue;
            }
            member_id_set.add(member_id);
            List<Object> item = new ArrayList<>();
            item.add(record.getString("username"));
            String phone = record.getString("phone");
            if (!display_contact && StringUtils.isNotEmpty(phone)) {
                phone = hideMobile(phone, true);
            }
            item.add(phone);
            item.add(record.getString("surveylink"));
            item.add(record.getString("send_status"));
            item.add(record.getString("send_time"));
            if (check_submit.equals(1)) {
                item.add(RespondentStatusEnum.getDescByValue(record.getIntValue("survey_resp_status")));
            } else {
                item.add(record.getString("finished"));
            }
            item.add(member_maps.get(member_id).get(0));
            rowList.add(item);
        }
        if (check_submit.equals(1)) {
            emailDeliverService.getTitleHead(headRowList, Stream.of("姓名", "手机号码", "问卷链接", "发送状态", "发送时间", "答卷状态", "催答次数").collect(Collectors.toList()));
        } else {
            emailDeliverService.getTitleHead(headRowList, Stream.of("姓名", "手机号码", "问卷链接", "发送状态", "发送时间", "成功完成答卷", "催答次数").collect(Collectors.toList()));
        }
        head.add(headRowList);
        exportDataList.add(rowList);
        // sheet页名称-自定义，如果没有则传空
        List<String> sheetNameList = Stream.of("sheet1").collect(Collectors.toList());
        String ossPath = OssPathEnum.TEMP_DELIVER.getPath() + EMAILDELIVER_EXPORT + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN) + SEPARATOR;
        //return ExcelExportUtil.exportWithDynamicData2("投放清单明细", head, exportDataList, sheetNameList, response, ossService, ossPath, OssPathEnum.TEMP_DELIVER);
        //return ExcelExportUtil.exportWithDynamicData2("投放清单明细", head, exportDataList, sheetNameList, response, storageService, ossPath, OssPathEnum.TEMP_DELIVER);

        return deliverService.exportWithDynamicData("投放清单明细", head, exportDataList, sheetNameList, response, ossPath);
    }

    /**
     * 隐藏手机号中间几位
     *
     * @param phone
     * @param noThrow true：不抛出异常
     * @return
     */
    private String hideMobile(String phone, boolean noThrow) {
        if (!Validator.isMobile(phone)) {
            if (noThrow) {
                return "";
            }
            throw new BusinessException(String.valueOf(ValidationErrorCodeEnum.EMAIL_ERROR.getCode()), String.format("phone error: {%s}", phone));
        }
        return String.format("%s****%s", phone.substring(0, 3), phone.substring(8, phone.length() - 1));
    }

    /**
     * 根据过滤条件筛选联系人投放记录
     *
     * @param smsDeliver
     * @param filter_params
     * @param exclude_member_ids
     * @param project_id
     * @param member_maps
     * @return
     */
    private List<JSONObject> getSmsRecordByFilterParams(DeliverSmsDeliver smsDeliver, JSONObject filter_params, List<String> exclude_member_ids, String project_id, Map<String, List<Integer>> member_maps) {
        List<JSONObject> record_list = smsRecordsData(smsDeliver, filter_params, project_id, member_maps, true);
        if (CollectionUtils.isEmpty(exclude_member_ids)) {
            return record_list;
        }
        return record_list.stream().filter(one -> !exclude_member_ids.contains(one.getString("member_id"))).collect(Collectors.toList());
    }

    private List<JSONObject> smsRecordsData(DeliverSmsDeliver smsDeliver, JSONObject filter_params, String project_id, Map<String, List<Integer>> member_maps, boolean use_aggergate) {
        Boolean urged = filter_params.getBoolean("urged");
        Object status = filter_params.get("status");
        String survey_status = filter_params.getString("survey_status");
        String survey_resp_status_arg = filter_params.getString("survey_resp_status");
        String search = filter_params.getString("search");
        Object sType = filter_params.get("s_type");
        String deliver_id = smsDeliver.getDeliverId();
        String deliverGroupId = smsDeliver.getDeliverGroupId();
        Integer check_submit = smsDeliver.getCheckSubmit();
        if (Objects.nonNull(member_maps)) {
            Map<String, List<Integer>> tmp = emailDeliverService.getDeliverDataMember(urged, survey_status, deliverGroupId, deliver_id, null);
            member_maps.putAll(tmp);
        } else {
            member_maps = emailDeliverService.getDeliverDataMember(urged, survey_status, deliverGroupId, deliver_id, null);
        }
        Set<String> member_surveydata_ids = member_maps.keySet();
        List<String> member_ids;
        if (urged != null) {
            member_ids = new ArrayList<>(member_surveydata_ids);
        } else {
            member_ids = deliverService.getDeliverMemberIdList(deliver_id, DeliverTtypeEnum.DELIVER_TTYPE_EMAIL);
        }
        Map<String, Integer> member_resp_maps = new HashMap<>();
        deliverService.getMemberRespMaps(project_id, survey_resp_status_arg, deliver_id, check_submit, member_resp_maps, member_ids);
        Set<String> member_resp_ids = member_resp_maps.keySet();

        LambdaQueryWrapper<DeliverSmsRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DeliverSmsRecord::getSmsDeliverId, smsDeliver.getId());
        if (Objects.nonNull(status)) {
            if (status instanceof Integer) {
                wrapper.eq(DeliverSmsRecord::getStatus, status);
            } else {
                wrapper.in(DeliverSmsRecord::getStatus, status);
            }
        }
        wrapper.and(StrUtil.isNotBlank(search), wrap -> wrap.like(DeliverSmsRecord::getUsername, search).or().like(DeliverSmsRecord::getPhone, search));

        if (urged != null || StrUtil.isNotBlank(survey_resp_status_arg)) {
            member_ids = new ArrayList<>(CollectionUtils.intersection(member_surveydata_ids, new HashSet<>(member_resp_ids)));
            wrapper.in(!CollectionUtils.isEmpty(member_ids), DeliverSmsRecord::getMemberId, member_ids);
        }
        if (Objects.nonNull(sType)) {
            if (sType instanceof Integer) {
                wrapper.eq(DeliverSmsRecord::getSType, sType);
            } else {
                wrapper.in(DeliverSmsRecord::getSType, sType);
            }
        }
        if (use_aggergate) {
            List<JSONObject> record_list = new ArrayList<>();
            wrapper.orderByAsc(DeliverSmsRecord::getId);
            List<DeliverSmsRecord> records = deliverSmsRecordMapper.selectList(wrapper);
            record2JsonObject(record_list, check_submit, member_resp_maps, records, member_maps);
            return record_list;
        }
        wrapper.orderByDesc(DeliverSmsRecord::getCreatedDt);
        return deliverSmsRecordMapper.selectList(wrapper).stream().map(one -> (JSONObject) JSONObject.toJSON(one)).collect(Collectors.toList());
    }

    /**
     * 根据选中的联系人获取投放记录
     *
     * @param smsDeliver
     * @param project_id
     * @param member_ids
     * @return
     */
    private List<JSONObject> getEmailRecordBySelect(DeliverSmsDeliver smsDeliver, String project_id, List<String> member_ids, Map<String, List<Integer>> member_maps) {
        if (Objects.nonNull(member_maps)) {
            Map<String, List<Integer>> tmp = emailDeliverService.getDeliverDataMember(null, null, smsDeliver.getDeliverGroupId(), smsDeliver.getDeliverId(), member_ids);
            member_maps.putAll(tmp);
        } else {
            member_maps = emailDeliverService.getDeliverDataMember(null, null, smsDeliver.getDeliverGroupId(), smsDeliver.getDeliverId(), member_ids);
        }

        List<JSONObject> record_list = new ArrayList<>();
        Map<String, Integer> member_resp_maps = new HashMap<>();
        Integer check_submit = smsDeliver.getCheckSubmit();
        if (check_submit.equals(0)) {
            for (String member_id : member_ids) {
                //Integer finished = surveyGrpcClient.getDeliverMemberRespTotalCount(smsDeliver.getDeliverId(), member_id, project_id);
                Integer finished = surveyGrpcClient.getDeliverRspdAmount(smsDeliver.getDeliverId(), null, null, member_id, RESPONDENT_STATUS_FINISH.getValue(), null, project_id);
                member_resp_maps.put(member_id, finished);
            }
        } else {
            for (String member_id : member_ids) {
                //Integer survey_resp_status = surveyGrpcClient.getDeliverRespStatus(smsDeliver.getDeliverId(), member_id, project_id);
                Integer survey_resp_status = surveyGrpcClient.getDeliverRspdStatus(smsDeliver.getDeliverId(), member_id, null, null, project_id);
                member_resp_maps.put(member_id, survey_resp_status);
            }
        }

        LambdaQueryWrapper<DeliverSmsRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(DeliverSmsRecord::getId);
        queryWrapper.in(DeliverSmsRecord::getMemberId, member_ids);
        queryWrapper.eq(DeliverSmsRecord::getSmsDeliverId, smsDeliver.getId());
        List<DeliverSmsRecord> sms_records = deliverSmsRecordMapper.selectList(queryWrapper);
        log.info("email_records-->>{}", sms_records);
        record2JsonObject(record_list, check_submit, member_resp_maps, sms_records, member_maps);
        return record_list;
    }

    private void record2JsonObject(List<JSONObject> record_list, Integer check_submit, Map<String, Integer> member_resp_maps, List<DeliverSmsRecord> email_records, Map<String, List<Integer>> member_maps) {
        ArrayList<String> email_record_member_id = new ArrayList<>();
        for (DeliverSmsRecord record : email_records) {
            String member_id = record.getMemberId();
            if (email_record_member_id.contains(member_id)) {
                continue;
            } else {
                email_record_member_id.add(member_id);
            }
            JSONObject item = new JSONObject();
            item.put("member_id", record.getMemberId());
            item.put("username", record.getUsername());
            item.put("phone", record.getPhone());
            if (check_submit.equals(0)) {
                item.put("finished", Optional.ofNullable(member_resp_maps.get(member_id)).orElse(0));
            } else {
                item.put("survey_resp_status", Optional.ofNullable(member_resp_maps.get(member_id)).orElse(RESPONDENT_STATUS_NOTSTART.getValue()));
            }
            item.put("surveylink", JSONObject.parseObject(record.getParams()).getString("surveylink"));
            List<Integer> nums = member_maps.getOrDefault("member_id", Arrays.asList(0, 0, DELIVERSURVEYDATA_SURVEY_STATUS_UNANSWER.getValue()));
            item.put("survey_nums", nums.get(2));
            item.put("survey_status", nums.get(1));
            item.put("urge_nums", nums.get(0));
            item.put("send_status", EmailRecordStatusEnum.getDescByValue(record.getStatus()));
            item.put("send_time", record.getCreatedDt().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
            record_list.add(item);
        }
        //反转
        Collections.reverse(record_list);
    }


    @Override
    public ServiceResult<?> smsDeliverRecord(Page<DeliverSmsRecord> page, SmsRecordsPageParam param) {
        String projectId = param.getProjectId();
        String smsDeliverId = param.getSmsDeliverId();
        DeliverSmsDeliver smsDeliver = originGetSmsDeliver(smsDeliverId);
        String status = param.getStatus();
        String search = param.getSearch();
        Boolean urged = Objects.nonNull(param.getUrged()) ? Boolean.valueOf(param.getUrged()) : null;
        String deliverGroupId = smsDeliver.getDeliverGroupId();
        String deliverId = smsDeliver.getDeliverId();

        Integer checkSubmit = smsDeliver.getCheckSubmit();
        String surveyRespStatus = param.getSurveyRespStatus();
        List<String> memberIds = deliverService.getDeliverMemberIdList(deliverId, DELIVER_TTYPE_SMS);
        Map<String, List<Integer>> memberMap = null;
        Map<String, Integer> memberRespMaps = new HashMap<>();
        if (Objects.nonNull(urged) || Objects.nonNull(surveyRespStatus)) {
            //没有催答和问卷相关的数据筛选，这些数据等到分页完成后再从数据库里查询
            if (Objects.nonNull(urged)) {
                memberMap = emailDeliverService.getDeliverDataMember(urged, param.getSurveyStatus(), deliverGroupId, deliverId, null);
                if (CollUtil.isNotEmpty(memberMap)) {
                    memberIds = new ArrayList<>(memberMap.keySet());
                    if (Objects.nonNull(surveyRespStatus)) {
                        getMemberRespMaps(memberIds, surveyRespStatus, memberRespMaps, deliverId, projectId);
                        if (memberRespMaps.isEmpty()) {
                            return ServiceResult.success(Collections.emptyList());
                        }
                        memberIds = new ArrayList<>(memberRespMaps.keySet());
                    } else {
                        deliverService.getMemberRespMaps(projectId, surveyRespStatus, deliverId, checkSubmit, memberRespMaps, memberIds);
                    }
                } else {
                    //当参数中有urge_nums or survey_status or survey_nums 参数时，没有结果则直接返回
                    return ServiceResult.success(Collections.emptyList());
                }
            } else {
                getMemberRespMaps(memberIds, surveyRespStatus, memberRespMaps, deliverId, projectId);
                if (memberRespMaps.isEmpty()) {
                    return ServiceResult.success(Collections.emptyList());
                }
                memberIds = new ArrayList<>(memberRespMaps.keySet());
            }
        }
        LambdaQueryWrapper<DeliverSmsRecord> queryWrapper = new LambdaQueryWrapper<>();
        if ((Objects.nonNull(urged)) || Objects.nonNull(surveyRespStatus)) {
            if (memberIds.isEmpty()) {
                return ServiceResult.success(Collections.emptyList());
            }
            queryWrapper.in(DeliverSmsRecord::getMemberId, memberIds);
        }
        commonWrapper(queryWrapper, status, smsDeliverId, search);
        //s_type 为投放或二次投放
        queryWrapper.in(DeliverSmsRecord::getSType, SMSRECORD_S_TYPE_DELIVER.getNumber(), SMSRECORD_S_TYPE_AGAIN_DELIVER.getNumber());
        //只查询去重的member_id
        queryWrapper.select(DeliverSmsRecord::getMemberId, DeliverSmsRecord::getId);
        queryWrapper.groupBy(DeliverSmsRecord::getMemberId, DeliverSmsRecord::getId);
        queryWrapper.orderByDesc(DeliverSmsRecord::getMemberId);
        List<DeliverSmsRecord> deliverSmsRecords = deliverSmsRecordMapper.selectPage(page, queryWrapper).getRecords().stream().filter(v -> Objects.nonNull(v.getMemberId())).collect(Collectors.toList());
        if (deliverSmsRecords.isEmpty()) {
            return ServiceResult.success(Collections.emptyList());
        }
        List<String> page_member_ids = new ArrayList();
        List<String> sms_record_ids = new ArrayList<>();
        //List page_member_mproject_ids = new ArrayList();
        deliverSmsRecords.forEach(v -> {
            page_member_ids.add(v.getMemberId());
            sms_record_ids.add(v.getId());
            //page_member_mproject_ids.add(v.getMemberId());
        });
        //生成member_map
        if (CollUtil.isEmpty(memberMap)) {
            LambdaQueryWrapper<DeliverDeliverSurveyData> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(DeliverDeliverSurveyData::getMemberId, page_member_ids);
            if (StrUtil.isNotEmpty(deliverGroupId)) {
                wrapper.eq(DeliverDeliverSurveyData::getDeliverGroupId, deliverGroupId);
            } else {
                wrapper.eq(DeliverDeliverSurveyData::getDeliverId, deliverId);
            }
            List<DeliverDeliverSurveyData> deliverDeliverSurveyData = deliverDeliverSurveyDataMapper.selectList(wrapper);
            memberMap = deliverDeliverSurveyData.stream().collect(Collectors.toMap(DeliverDeliverSurveyData::getMemberId, v -> Arrays.asList(v.getUrgeNums(), v.getSurveyNums(), v.getSurveyStatus()), (a, b) -> a));
        }
        //生成respondent的
        if (CollUtil.isEmpty(memberRespMaps)) {
            getMemberRespMaps2(projectId, surveyRespStatus, deliverId, checkSubmit, memberRespMaps, page_member_ids);
        }
        boolean displayContact;
        if (CollectionUtils.isNotEmpty(page_member_ids) && StringUtils.isEmpty(param.getDisplayContact())) {
            displayContact = memberGrpcClient.checkDisplayRangePermission(SecurityContextHolder.getOrgId(), SecurityContextHolder.getUserId(), page_member_ids.get(0));
        } else {
            displayContact = false;
        }
        Map<String, DeliverSmsRecordVo> res = new HashMap();
        if (!sms_record_ids.isEmpty()) {
            List<DeliverSmsRecord> list = deliverSmsRecordMapper.selectBatchIds(sms_record_ids);
            for (DeliverSmsRecord v : list) {
                res.put(v.getMemberId(), setItem(v, checkSubmit, memberMap, memberRespMaps, displayContact));
            }
        }
        List<DeliverSmsRecordVo> rows = new ArrayList<>(page_member_ids.size());
        //按分页顺序整理数据
        page_member_ids.forEach(v -> rows.add(res.get(v)));
        return ServiceResult.success(rows);
    }

    private void getMemberRespMaps(List<String> memberIds, String surveyRespStatus, Map<String, Integer> memberRespMaps, String deliverId, String projectId) {
        List<List<String>> mem_ids_list = ListUtil.partition(memberIds, 3000);
        for (List<String> mem_ids : mem_ids_list) {
            if (String.valueOf(RespondentStatusEnum.RESPONDENT_STATUS_NOTSTART.getValue()).equals(surveyRespStatus)) {
                List<JSONObject> respondent_list = surveyGrpcClient.getDeliverRspdStatusBatch(deliverId, mem_ids, null, projectId);
                List<String> resp_member_id_list = respondent_list.stream().map(it -> it.getString("member_id")).collect(Collectors.toList());
                deliverService.fillNoStart(memberRespMaps, mem_ids, resp_member_id_list);
            } else {
                List<JSONObject> respondent_list = surveyGrpcClient.getDeliverRspdStatusBatch(deliverId, mem_ids, surveyRespStatus, projectId);
                for (JSONObject resp : respondent_list) {
                    String rstatus = resp.getString("status");
                    if (rstatus.equals(surveyRespStatus) && RESPONDENT_STATUS.contains(rstatus)) {
                        memberRespMaps.put(resp.getString("member_id"), Integer.valueOf(rstatus));
                    }
                }
            }
        }
    }


    private DeliverSmsRecordVo setItem(DeliverSmsRecord item, Integer checkSubmit, Map<String, List<Integer>> memberMap, Map<String, Integer> memberRespMaps, boolean displayContact) {
        String memberId = item.getMemberId();
        DeliverSmsRecordVo vo = deliverConvertMapper.smsRecord2Vo(item);
        int urge_n, survey_n, survey_s;
        if (memberMap.containsKey(memberId)) {
            List<Integer> list = memberMap.get(memberId);
            urge_n = list.stream().findFirst().orElse(0);
            survey_n = list.get(1);
            survey_s = list.get(2);
        } else {
            urge_n = 0;
            survey_n = 0;
            survey_s = DELIVERSURVEYDATA_SURVEY_STATUS_UNANSWER.getValue();
        }
        vo.setUrgeNums(urge_n);
        vo.setSurveyNums(survey_n);
        vo.setSurveyStatus(survey_s);
        if (checkSubmit == 0) {
            vo.setFinished(memberRespMaps.getOrDefault(memberId, 0));
        } else {
            vo.setSurveyRespStatus(memberRespMaps.getOrDefault(memberId, RESPONDENT_STATUS_NOTSTART.getValue()));
        }
        if (!displayContact && StringUtils.isNotEmpty(vo.getPhone())) {
            vo.setPhone(hideMobile(vo.getPhone(), true));
        }
        return vo;
    }

    public void getMemberRespMaps2(String project_id, String survey_resp_status_arg, String deliver_id, Integer check_submit, Map<String, Integer> member_resp_maps, List<String> member_ids) {
        if (check_submit.equals(0)) {
            for (String member_id : member_ids) {
                //Integer finished = surveyGrpcClient.getDeliverMemberRespTotalCount(deliver_id, member_id, project_id);
                Integer finished = surveyGrpcClient.getDeliverRspdAmount(deliver_id, null, null, member_id, RESPONDENT_STATUS_FINISH.getValue(), null, project_id);
                member_resp_maps.put(member_id, finished);
            }
        } else {
            for (String member_id : member_ids) {
                Integer survey_resp_status;
                if (String.valueOf(RespondentStatusEnum.RESPONDENT_STATUS_NOTSTART.getValue()).equals(survey_resp_status_arg)) {
                    survey_resp_status = surveyGrpcClient.getDeliverRspdStatus(deliver_id, member_id, null, null, project_id);
                } else {
                    survey_resp_status = surveyGrpcClient.getDeliverRspdStatus(deliver_id, member_id, null, Objects.nonNull(survey_resp_status_arg) ? Integer.valueOf(survey_resp_status_arg) : null, project_id);
                }
                if (StrUtil.isNotEmpty(survey_resp_status_arg)) {
                    if (String.valueOf(survey_resp_status).equals(survey_resp_status_arg) && RESPONDENT_STATUS.contains(String.valueOf(survey_resp_status))) {
                        member_resp_maps.put(member_id, survey_resp_status);
                    }
                } else if (RESPONDENT_STATUS.contains(String.valueOf(survey_resp_status))) {
                    member_resp_maps.put(member_id, survey_resp_status);
                }
            }
        }
    }

    private void commonWrapper(LambdaQueryWrapper<DeliverSmsRecord> queryWrapper, String status, String smsDeliverId, String search) {
        queryWrapper.eq(DeliverSmsRecord::getSmsDeliverId, smsDeliverId);
        queryWrapper.eq(StringUtils.isNotEmpty(status), DeliverSmsRecord::getStatus, status);
        queryWrapper.and(StringUtils.isNotEmpty(search), wrapper -> wrapper.like(DeliverSmsRecord::getUsername, search).or().like(DeliverSmsRecord::getPhone, search));
    }

    @Override
    public ServiceResult<?> updateSmsDelivers(String id, JSONObject param) {
        DeliverSmsDeliver smsDeliver = baseMapper.selectById(id);
        if (Objects.isNull(smsDeliver)) {
            throw new BusinessException(AppResourceErrorCode.NOT_FOUND.toString(), String.format("SMSDeliver[id=%s] not found", id));
        }
        if (param.containsKey("sms_template_id") && StringUtils.isEmpty((String) param.get("sms_template_id"))) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "短信模板sms_template_id不能为空");
        }
        return updateSmsDeliver(smsDeliver, param);
    }

    @Override
    public ServiceResult<?> smsDeliverAgain(String id, JSONObject param, DeliverSmsDeliver smsDeliver) {
        String orgId = SecurityContextHolder.getOrgId();
        String userId = SecurityContextHolder.getUserId();
        //sms_deliver.is_mproject  项目经理投放 对应数据库无此字段
        List<String> member_ids;
        DeliverDeliver new_deliver;
        if (param.containsKey("member_ids")) {
            member_ids = param.getJSONArray("member_ids").toJavaList(String.class);
            if (CollectionUtils.isEmpty(member_ids)) {
                return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "缺少联系人");
            }
        } else {
            JSONObject filter_params = (JSONObject) param.getOrDefault("filter_params", new JSONObject());
            List<String> exclude_member_ids = CollectionUtils.isEmpty(param.getJSONArray("exclude_member_ids")) ? Collections.emptyList() : param.getJSONArray("exclude_member_ids").toJavaList(String.class);

            //勾选全部重新投放不可选择"黑名单拦截"发送状态
            String status = filter_params.getString("status");
            if (String.valueOf(SMSRECORD_STATUS_MEMBER_BLACKLIST.getValue()).equals(status)) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "黑名单用户无法重新投放");
            }
            member_ids = smsDeliverRecordMembers(smsDeliver, filter_params, exclude_member_ids, id);
        }
        new_deliver = smsDeliverRecastBySelect(orgId, smsDeliver, id, member_ids, userId);
        Map<String, String> res = new HashMap<>(4);
        res.put("id", new_deliver.getId());
        res.put("deliver_name", new_deliver.getName());
        return ServiceResult.success(res);
    }

    /**
     * 返回短信投放中的符合条件的联系人
     *
     * @param smsDeliver
     * @param filter_params
     * @param exclude_member_ids
     * @param project_id
     */
    private List<String> smsDeliverRecordMembers(DeliverSmsDeliver smsDeliver, JSONObject filter_params, List<String> exclude_member_ids, String project_id) {
        List<JSONObject> tmp = smsRecordsData(smsDeliver, filter_params, project_id, null, false);
        List<DeliverSmsRecord> sms_records = JSONObject.parseArray(JSONArray.toJSONString(tmp), DeliverSmsRecord.class);
        return sms_records.stream().map(DeliverSmsRecord::getMemberId).filter(v -> !exclude_member_ids.contains(v)).distinct().collect(Collectors.toList());
    }

    /**
     * 选中联系人的短信重新投放
     *
     * @param orgId
     * @param smsDeliver
     * @param id
     * @param member_ids
     * @param userId
     * @return
     */
    private DeliverDeliver smsDeliverRecastBySelect(String orgId, DeliverSmsDeliver smsDeliver, String id, List<String> member_ids, String userId) {
        DeliverDeliver deliver = emailDeliverService.getDeliver(smsDeliver.getDeliverId());
        DeliverRecast deliverRecast = emailDeliverService.getOneRecast(smsDeliver.getDeliverId());
        DeliverDeliverGroup deliverDeliverGroup = StrUtil.isNotEmpty(smsDeliver.getDeliverGroupId()) ? emailDeliverService.originGetDeliverGroup(smsDeliver.getDeliverGroupId()) : null;
        String deliverGroupId = Optional.ofNullable(deliverDeliverGroup).map(DeliverDeliverGroup::getId).orElse(null);
        String recast_nums = Objects.isNull(deliverRecast) ? "1" : String.valueOf(JSON.parseArray(deliverRecast.getChildrenDeliver()).size() + 1);
        List<String> new_member_list = new ArrayList<>();
        member_ids.forEach(v -> {
            if (emailDeliverService.checkMemberDeliverUrgeStatus(v, deliverGroupId, deliver.getId())) {
                new_member_list.add(v);
            }
        });
        if (new_member_list.isEmpty()) {
            throw new BusinessException(String.valueOf(ResourceErrorCodeEnum.STATUS_CHANGED.getCode()), "没有可重新投放的联系人");
        }
        JSONObject new_deliver_params = emailDeliverService.buildRecastParams(deliver, recast_nums, deliverDeliverGroup, null, smsDeliver);
        new_deliver_params.put("member_id_list", new_member_list);
        new_deliver_params.put("orgId", orgId);
        new_deliver_params.put("user_id", userId);
        new_deliver_params.put("template", smsDeliver.getTemplate());
        new_deliver_params.put("length", smsDeliver.getLength());
        log.info("开始创建短信投放{}", new_deliver_params);
        String new_deliver_id = createSmsDeliver(JSON.toJavaObject(new_deliver_params, SmsDeliversParamAgain.class));
        emailDeliverService.createOrUpdateRecast(orgId, smsDeliver.getDeliverId(), new_deliver_id);
        DeliverDeliver deliverRes = deliverDeliverMapper.selectById(new_deliver_id);
        triggerDeliverStatus(deliverRes, "done");
        return emailDeliverService.getDeliver(new_deliver_id);
    }
}